package net.sourceforge.peers.gui;

import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import net.sourceforge.peers.Config;
import net.sourceforge.peers.Logger;
import net.sourceforge.peers.media.AbstractSoundManager;
import net.sourceforge.peers.media.MediaManager;
import net.sourceforge.peers.sip.RFC3261;
import net.sourceforge.peers.sip.Utils;
import net.sourceforge.peers.sip.core.useragent.SipListener;
import net.sourceforge.peers.sip.core.useragent.UserAgent;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaderFieldName;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaderFieldValue;
import net.sourceforge.peers.sip.syntaxencoding.SipHeaders;
import net.sourceforge.peers.sip.syntaxencoding.SipUriSyntaxException;
import net.sourceforge.peers.sip.transactionuser.Dialog;
import net.sourceforge.peers.sip.transactionuser.DialogManager;
import net.sourceforge.peers.sip.transport.SipMessage;
import net.sourceforge.peers.sip.transport.SipRequest;
import net.sourceforge.peers.sip.transport.SipResponse;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * GUI界面事件管理器
 *
 * @author Mr.Yan
 */
public class EventManager implements SipListener, MainFrameListener,
        CallFrameListener, ActionListener {

    public static final String ACTION_ACCOUNT = "Account";
    public static final String ACTION_RING = "Ring";

    private UserAgent userAgent;
    private final MainFrame mainFrame;
    private AccountFrame accountFrame;
    private final Map<String, CallFrame> callFrames;
    private boolean closed;
    private final Logger logger;
//    Player player;
    String filename= "D://music.mp3";//文件路径;

    public EventManager(MainFrame mainFrame, String peersHome,
                        Logger logger, AbstractSoundManager soundManager) {
        this.mainFrame = mainFrame;
        this.logger = logger;
        callFrames = Collections.synchronizedMap(new HashMap<>());
        closed = false;
        try {
            userAgent = new UserAgent(this, peersHome, logger, soundManager);
        } catch (SocketException e) {
            SwingUtilities.invokeLater(() -> {
                JOptionPane.showMessageDialog(null, "Peers sip port " +
                                "unavailable, about to leave", "Error",
                        JOptionPane.ERROR_MESSAGE);
                System.exit(1);
            });
        }


    }

    // sip events
    @Override
    public void registering(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(() -> {
            if (accountFrame != null) {
                accountFrame.registering();
            }
            mainFrame.registering();
        });

    }

    @Override
    public void registerFailed(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(() -> {
            if (accountFrame != null) {
                accountFrame.registerFailed();
            }
            mainFrame.registerFailed();
        });

    }

    @Override
    public void registerSuccessful(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(() -> {
            if (closed) {
                userAgent.close();
                System.exit(0);
                return;
            }
            if (accountFrame != null) {
                accountFrame.registerSuccess();
            }
            mainFrame.registerSuccessful();
        });

    }

    @Override
    public void calleePickup(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(() -> {
            CallFrame callFrame = getCallFrame(sipResponse);
            if (callFrame != null) {
                callFrame.calleePickup();
            }
        });

    }

    @Override
    public void error(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(() -> {
            CallFrame callFrame = getCallFrame(sipResponse);
            if (callFrame != null) {
                callFrame.error(sipResponse);
            }
        });

    }

    @Override
    public void incomingCall(final SipRequest sipRequest,
                             SipResponse provResponse) {
        SwingUtilities.invokeLater(() -> {
            try {

                BufferedInputStream buffer = new BufferedInputStream(new FileInputStream(filename));
               Player  player = new Player(buffer);//加载
                SipHeaders sipHeaders = sipRequest.getSipHeaders();
                SipHeaderFieldName sipHeaderFieldName = new SipHeaderFieldName(RFC3261.HDR_FROM);
                SipHeaderFieldValue from = sipHeaders.get(sipHeaderFieldName);
                final String fromValue = from.getValue();
                String callId = Utils.getMessageCallId(sipRequest);
                CallFrame callFrame = new CallFrame(fromValue, callId, EventManager.this, logger,player);
                callFrames.put(callId, callFrame);
                callFrame.setSipRequest(sipRequest);
                callFrame.incomingCall();
            } catch (FileNotFoundException | JavaLayerException e) {
                e.printStackTrace();
            }


        });

    }

    @Override
    public void remoteHangup(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(() -> {
            CallFrame callFrame = getCallFrame(sipRequest);
            if (callFrame != null) {
                callFrame.remoteHangup();
            }
        });

    }

    @Override
    public void ringing(final SipResponse sipResponse) {
        SwingUtilities.invokeLater(() -> {
            CallFrame callFrame = getCallFrame(sipResponse);
            if (callFrame != null) {
                callFrame.ringing();
            }
        });

    }

    // 主窗体event

    @Override
    //注册  userAgent.register
    public void register() {
        if (userAgent == null) {
            return;
        }
        SwingUtilities.invokeLater(() -> {
            //读取配置信息
            Config config = userAgent.getConfig();
            if (config.getPassword() != null) {
                try {
                    userAgent.register();
                } catch (SipUriSyntaxException e) {
                    mainFrame.setLabelText(e.getMessage());
                }
            }
        });

    }

    @Override
    //拨打按钮按下  userAgent.invite
    public void callClicked(final String uri) {
        SwingUtilities.invokeLater(() -> {
            String callId = Utils.generateCallID(userAgent.getConfig().getLocalInetAddress());
            CallFrame callFrame = new CallFrame(uri, callId, EventManager.this, logger);
            callFrames.put(callId, callFrame);
            SipRequest sipRequest;
            try {
                sipRequest = userAgent.invite(uri, callId);
                mainFrame.setLabelText2("");

            } catch (SipUriSyntaxException e) {
                logger.error(e.getMessage(), e);
                Date dNow = new Date( );
                SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
//                mainFrame.setLabelText(e.getMessage());
                mainFrame.setLabelText2("请求地址无效 "+ft.format(dNow));
                return;
            }
            callFrame.setSipRequest(sipRequest);
            //状态机转化init->UAC
            callFrame.callClicked();
        });

    }

    @Override
    //关闭窗口  userAgent.unregister()
    public void windowClosed() {
        SwingUtilities.invokeLater(() -> {
            try {
                userAgent.unregister();
            } catch (Exception e) {
                logger.error("error while unregistering", e);
            }
            closed = true;
            try {
                Thread.sleep(3 * RFC3261.TIMER_T1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.exit(0);
        });
    }

    // call frame events

    @Override
    //挂断 userAgent.terminate
    public void hangupClicked(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(() -> userAgent.terminate(sipRequest));
    }

    @Override
    //接听 userAgent.acceptCall
    public void pickupClicked(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(() -> {
            String callId = Utils.getMessageCallId(sipRequest);
            DialogManager dialogManager = userAgent.getDialogManager();
            Dialog dialog = dialogManager.getDialog(callId);
            userAgent.acceptCall(sipRequest, dialog);
        });
    }

    @Override
    //拒接 userAgent.rejectCall
    public void busyHereClicked(final SipRequest sipRequest) {
        SwingUtilities.invokeLater(() -> userAgent.rejectCall(sipRequest));

    }

    @Override
    //按键 只做音频传递
    public void dtmf(final char digit) {
        SwingUtilities.invokeLater(() -> {
            MediaManager mediaManager = userAgent.getMediaManager();
            mediaManager.sendDtmf(digit);
        });
    }

    //根据callID获取CallFrame
    private CallFrame getCallFrame(SipMessage sipMessage) {
        String callId = Utils.getMessageCallId(sipMessage);
        return callFrames.get(callId);
    }

    //顶部按钮点击事件
    public void actionPerformed(ActionEvent e) {
        String action = e.getActionCommand();
        logger.debug("gui actionPerformed() " + action);
        Runnable runnable = null;
        if (ACTION_ACCOUNT.equals(action)) {
            runnable = () -> {
                if (accountFrame == null ||
                        !accountFrame.isDisplayable()) {
                    accountFrame = new AccountFrame(userAgent, logger);
                    //显示配置窗口
                    accountFrame.setVisible(true);
                } else {
                    accountFrame.requestFocus();
                }
            };
        }

        if (ACTION_RING.equals(action)) {
            runnable = () -> {
                JFileChooser jFileChooser = new JFileChooser("D://bishe_ring");
                jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
                int res = jFileChooser.showOpenDialog(null);
                if (res == JFileChooser.APPROVE_OPTION) {


                        File file = jFileChooser.getSelectedFile();
//                        BufferedInputStream buffer = new BufferedInputStream(new FileInputStream(file.getAbsolutePath()));
                        filename=file.getAbsolutePath();

                }

            };
        }

        if (runnable != null) {
            SwingUtilities.invokeLater(runnable);
        }
    }

}
